import 'dart:async';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:package_info/package_info.dart';
import 'package:path_provider/path_provider.dart';
import 'package:t_upgrade_plugin/model/upgrade_data.dart';
import 'package:t_upgrade_plugin/network/upgrade_service.dart';
import 'package:t_upgrade_plugin/page/upgrade/fond_new_version_dialog.dart';
import 'package:t_upgrade_plugin/page/upgrade/upgrade_dialog.dart';
import 'package:common/common.dart';

import '../t_upgrade_plugin.dart';

class AppVersionBloc extends Bloc<AppVersionEvent, AppVersionState> {
  static String blocName = 'AppVersionBloc';
  static String _IGNORE_VERSION_KEY = 'ignore_version_key';
  static String _LOCAL_VERSION = 'local_version';
  Timer timer;
  Duration _durationTime = Duration(seconds: 1);

  AppVersionBloc(AppVersionState initialState) : super(initialState) {
    _currentState = initialState;
  }

  AppVersionState _currentState;
  BuildContext _context;

  @override
  Stream<AppVersionState> mapEventToState(AppVersionEvent event) async* {
    if (event is CheckAppVersion) {
      _cleanFile();
      _context = event.context;
      _currentState.isManualCheck = event.isManualCheck;
      _checkAppUpgrade(
        event.tenantAppId,
        channelCode: event.channelCode,
        storeCode: event.storeCode,
        deviceUuid: event.deviceUuid,
      );
      return;
    }
    if (event is _CheckResultEvent) {
      UpgradeData upgradeData = event.upgradeData;
      if (upgradeData == null) {
        return;
      }
      _currentState.upgradeData = upgradeData;

      ///TODO 如果当前版本小于最低版本，也需要强制升级，这里逻辑需要加一下啊
      switch (upgradeData.forceUpdate) {
        case 0:
          _currentState.updateType = UpdateType.FORCE;
          break;
        case 1:
          _currentState.updateType = UpdateType.SIMPLE;
          break;
        case 3:
          _currentState.updateType = UpdateType.IGNORE;
          var sp = await TPreferences().get;
          String ignoreVersion = sp.getString(_IGNORE_VERSION_KEY) ?? "";
          if (!_currentState.isManualCheck &&
              ignoreVersion.contains(upgradeData.version)) {
            return;
          }
          break;
      }
      UpgradeDialog.show(_context);
      return;
    }

    if (event is NowUpdateEvent) {
      timer?.cancel();
      timer = Timer(_durationTime, () {
        if (Platform.isAndroid) {
          _androidNowUpdate();
        }
        if (Platform.isIOS) {
          try {
            launch("https://apps.apple.com/us/app/%E5%93%81%E9%81%93%E5%B7%A5%E4%BD%9C%E7%AB%99/id1531667320");
          }catch(e){
            Fluttertoast.showToast(msg: "请通过AppStore升级。");
          }
        }
      });
    }

    if (event is _ProgressEvent) {
      if (event.progress >= 1) {
        _currentState.downLoadType = DownLoadType.DOWNLOAD_SUCCESS;
      } else {
        _currentState.downLoadType = DownLoadType.DOWNLOAD;
      }
      _currentState.progress = event.progress;
      yield _currentState.copy();
      return;
    }

    if (event is DownLoadErrorEvent) {
      _currentState.downLoadType = DownLoadType.ERROR;
      yield _currentState.copy();
      return;
    }

    if (event is InstallApkEvent) {
      TUpgradePlugin.installApk(_currentState.appFilePatch);
      return;
    }

    if (event is IgnoreThisVersion) {
      TPreferences().get.then((value) {
        String ignoreVersion = value.getString(_IGNORE_VERSION_KEY) ?? "";
        String thisVersion = _currentState.upgradeData.version;
        if (!ignoreVersion.contains(thisVersion)) {
          ignoreVersion = "$ignoreVersion,$thisVersion";
          value.setString(_IGNORE_VERSION_KEY, ignoreVersion);
        }
      });
    }
  }

  _cleanFile() async {
    // var sp = await TPreferences().get;
    // PackageInfo packageInfo = await PackageInfo.fromPlatform();
    // int thisVersion = int.parse(packageInfo.buildNumber);
    // int oldVersion = sp.get(_LOCAL_VERSION) ?? 0;
    // if (thisVersion > oldVersion) {
    //   Directory directory = await getApplicationDocumentsDirectory();
    //   File apkFile = File("${directory.path}/${_currentState.tenantAppId}.apk");
    //   if (apkFile.existsSync()) {
    //     apkFile.deleteSync();
    //   }
    //   sp.setInt(_LOCAL_VERSION, thisVersion);
    // }
    Directory directory = await getApplicationDocumentsDirectory();
    File apkFile = File("${directory.path}/${_currentState.tenantAppId}.apk");
    if (apkFile.existsSync()) {
      apkFile.deleteSync();
    }
  }

  _androidNowUpdate() async {
    Directory directory = await getApplicationDocumentsDirectory();
    String filePatch = "${directory.path}/${_currentState.tenantAppId}.apk";
    String tempPatch = "${directory.path}/${_currentState.tenantAppId}.temp";
    _currentState.appFilePatch = filePatch;
    bool exists = await File(filePatch).exists();
    if (exists) {
      add(_ProgressEvent(1));
    } else {
      File tempFile = File(tempPatch);
      if (tempFile.existsSync()) {
        tempFile.delete();
      }
      UpgradeService.downLoadFile(
          _currentState.upgradeData.downloadUrl, tempPatch, (received, total) {
        if (total != -1) {
          add(_ProgressEvent((received / total)));
          if (received >= total) {
            print(filePatch);
            File(tempPatch).renameSync(filePatch);
          }
        } else {
          add(DownLoadErrorEvent());
        }
      }).catchError((onError) {
        add(DownLoadErrorEvent());
      });
    }
  }

  _checkAppUpgrade(
    String tenantAppId, {
    String channelCode = "official",
    String storeCode,
    String deviceUuid,
  }) async {
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    print("版本信息：${packageInfo.buildNumber} and ${packageInfo.version}");
    _currentState.appVersion = "${packageInfo.version}.0";
    _currentState.tenantAppId = tenantAppId;
    Map<String, dynamic> parameters = {
      "tenantAppId": tenantAppId,
      "channelCode": channelCode,
      "version": _currentState.appVersion,
      "platform": Platform.operatingSystem
    };
    if (TUtil.isNotEmptyString(storeCode)) {
      parameters.addAll({"storeCode": storeCode});
    }
    if (TUtil.isNotEmptyString(deviceUuid)) {
      parameters.addAll({"deviceUuid": deviceUuid});
    }
    TComposer.compose(
        UpgradeService.checkAppVersion(parameters),
        TRequestCallback<UpgradeData>(
          showErrorMessageFromServer: false,
          onSuccess: (data) {
            add(_CheckResultEvent(data));
          },
          parse: (data) {
            return UpgradeData.fromJson(data);
          },
          onFailedCode: (code, message) {
            if (code == 30002 && _currentState.isManualCheck) {
              FondNewVersionDialog.show(_context, _currentState.appVersion);
            }
          },
        ));
  }

  @override
  Future<void> close() {
    timer?.cancel();
    return super.close();
  }
}

class _CheckResultEvent extends AppVersionEvent {
  final UpgradeData upgradeData;

  _CheckResultEvent(this.upgradeData);
}

///检查APP版本
class CheckAppVersion extends AppVersionEvent {
  final BuildContext context;
  final String tenantAppId;
  String channelCode;
  String storeCode;
  String deviceUuid;

  ///如果是手动检测
  bool isManualCheck;

  ///tenantAppId 应用appId
  ///channelCode 渠道号 不传默认官方渠道
  ///storeCode 门店号用于灰度
  ///deviceUuid 设备唯一编号，可用于灰度发布
  ///isManualCheck 手动检测APP升级，如果点击某个按钮检测需要传入true
  ///如果门店号和设备唯一号都传，后台需要同时命中这两个值才能恢复升级
  CheckAppVersion(
    this.context,
    this.tenantAppId, {
    this.channelCode = "official",
    this.storeCode,
    this.deviceUuid,
    this.isManualCheck = false,
  });
}

class IgnoreThisVersion extends AppVersionEvent {}

class InstallApkEvent extends AppVersionEvent {}

class NowUpdateEvent extends AppVersionEvent {}

class _ProgressEvent extends AppVersionEvent {
  final double progress;

  _ProgressEvent(this.progress);
}

class DownLoadErrorEvent extends AppVersionEvent {}

abstract class AppVersionEvent {}

class AppVersionState {
  String appFilePatch;
  UpgradeData upgradeData;
  UpdateType updateType = UpdateType.SIMPLE;
  DownLoadType downLoadType = DownLoadType.NON;
  String appVersion;
  String tenantAppId = "default";

  ///进度条[0,1]区间，等于1表示现在完成
  double progress = 0;
  bool isManualCheck;

  AppVersionState copy() {
    AppVersionState newState = AppVersionState();
    newState.appFilePatch = appFilePatch;
    newState.upgradeData = upgradeData;
    newState.updateType = updateType;
    newState.progress = progress;
    newState.downLoadType = downLoadType;
    newState.isManualCheck = isManualCheck;
    return newState;
  }
}

enum DownLoadType {
  NON,
  DOWNLOAD,
  DOWNLOAD_SUCCESS,
  ERROR,
}

enum UpdateType { FORCE, SIMPLE, IGNORE }
